
// # Example:
//
// Publish 'hello' to `topic` with QoS `0`:
// ```
// $ ./mqtt_client pub mqtt-tcp://127.0.0.1:1883 0 topic hello
// ```
//
// Subscribe to `topic` with QoS `0` and waiting for messages:
// ```
// $ ./mqtt_client sub mqtt-tcp://127.0.0.1:1883 0 topic
// ```
//

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <time.h>

#include "nng/mqtt/mqtt_client.h"
#include "nng/nng.h"
#include "nng/supplemental/util/platform.h"

// Subcommands
#define PUBLISH "pub"
#define SUBSCRIBE "sub"

void
fatal(const char *msg, int rv)
{
    fprintf(stderr, "%s: %s\n", msg, nng_strerror(rv));
}


static void
disconnect_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
{
    int reason = 0;
    // get connect reason
    nng_pipe_get_int(p, NNG_OPT_MQTT_DISCONNECT_REASON, &reason);
    // property *prop;
    // nng_pipe_get_ptr(p, NNG_OPT_MQTT_DISCONNECT_PROPERTY, &prop);
    // nng_socket_get?
    printf("%s: disconnected!\n", __FUNCTION__);
}

static void
connect_cb(nng_pipe p)
{
    int reason;
    // get connect reason
    nng_pipe_get_int(p, NNG_OPT_MQTT_CONNECT_REASON, &reason);
    // get property for MQTT V5
    // property *prop;
    // nng_pipe_get_ptr(p, NNG_OPT_MQTT_CONNECT_PROPERTY, &prop);
    printf("%s: connected!\n", __FUNCTION__);
}

// Connect to the given address.
int
client_connect(
    nng_socket *sock, nng_dialer *dialer, const char *url, bool verbose)
{
    int        rv;

    if ((rv = nng_mqtt_client_open(sock)) != 0) {
        fatal("nng_socket", rv);
        printf("nng_socket");
    }

    if ((rv = nng_dialer_create(dialer, *sock, url)) != 0) {
        fatal("nng_dialer_create", rv);
    }

    // create a CONNECT message
    /* CONNECT */
    nng_msg *connmsg;
    nng_mqtt_msg_alloc(&connmsg, 0);
    nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT);
    nng_mqtt_msg_set_connect_proto_version(connmsg, 4);
    nng_mqtt_msg_set_connect_keep_alive(connmsg, 60);
    nng_mqtt_msg_set_connect_user_name(connmsg, "test");
    nng_mqtt_msg_set_connect_password(connmsg, "test123");
    nng_mqtt_msg_set_connect_will_msg(
        connmsg, (uint8_t *) "bye-bye", strlen("bye-bye"));
    nng_mqtt_msg_set_connect_will_topic(connmsg, "will_topic");
    nng_mqtt_msg_set_connect_clean_session(connmsg, true);

    nng_mqtt_set_connect_cb(*sock, connect_cb, sock);
    nng_mqtt_set_disconnect_cb(*sock, disconnect_cb, connmsg);

    uint8_t buff[1024] = { 0 };

    if (verbose) {
        nng_mqtt_msg_dump(connmsg, buff, sizeof(buff), true);
        printf("%s\n", buff);
    }

    printf("Connecting to server ...\n");
    nng_dialer_set_ptr(*dialer, NNG_OPT_MQTT_CONNMSG, connmsg);
    nng_dialer_start(*dialer, NNG_FLAG_NONBLOCK);

    return (0);
}

// Publish a message to the given topic and with the given QoS.
int
client_publish(nng_socket sock, const char *topic, uint8_t *payload,
               uint32_t payload_len, uint8_t qos, bool verbose)
{
    int rv;

    // create a PUBLISH message
    nng_msg *pubmsg;
    nng_mqtt_msg_alloc(&pubmsg, 0);
    nng_mqtt_msg_set_packet_type(pubmsg, NNG_MQTT_PUBLISH);
    nng_mqtt_msg_set_publish_dup(pubmsg, 0);
    nng_mqtt_msg_set_publish_qos(pubmsg, qos);
    nng_mqtt_msg_set_publish_retain(pubmsg, 0);
    nng_mqtt_msg_set_publish_payload(
        pubmsg, (uint8_t *) payload, payload_len);
    nng_mqtt_msg_set_publish_topic(pubmsg, topic);

    if (verbose) {

    }

    printf("Publishing to '%s' ...\n", topic);
    if ((rv = nng_sendmsg(sock, pubmsg, NNG_FLAG_NONBLOCK)) != 0) {
        fatal("nng_sendmsg", rv);
    }

    return rv;
}

struct pub_params {
    nng_socket *sock;
    const char *topic;
    uint8_t *   data;
    uint32_t    data_len;
    uint8_t     qos;
    bool        verbose;
    uint32_t    interval;
};

struct pub_params params;

void
publish_cb(void *args)
{
    struct pub_params *params = args;
    do {
        client_publish(*params->sock, params->topic, params->data,
                       params->data_len, params->qos, params->verbose);
        nng_msleep(params->interval);
    } while (params->interval > 0);
    printf("thread_exit\n");
}



int
main()
{
    nng_socket sock;
    nng_dialer dialer;
    int rv;
    const char *url         = "mqtt-tcp://192.168.2.123:1883";
    uint8_t     qos         = 0;
    const char *topic       = "/test/mqttclint/sss";
    if ((rv = nng_mqtt_client_open(&sock)) != 0) {
        fatal("nng_socket", rv);
        printf("nng_socket");
    }

    if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) {
        fatal("nng_dialer_create", rv);
    }

    nng_msg *connmsg;
    nng_mqtt_msg_alloc(&connmsg, 0);
    nng_mqtt_msg_set_packet_type(connmsg, NNG_MQTT_CONNECT);
    nng_mqtt_msg_set_connect_proto_version(connmsg, 4);
    nng_mqtt_msg_set_connect_user_name(connmsg, "test");
    nng_mqtt_msg_set_connect_password(connmsg, "test123");

    nng_mqtt_set_connect_cb(sock, connect_cb, &sock);
    nng_mqtt_set_disconnect_cb(sock, disconnect_cb, connmsg);

    nng_dialer_set_ptr(dialer, NNG_OPT_MQTT_CONNMSG, connmsg);
    nng_dialer_start(dialer, NNG_FLAG_NONBLOCK);
    char qwes[8]={0};
    memset(qwes,' ',8);
    const char *data     = "{\"asdf\":\"qsdfg234er5t6y7uhg\"}";
    uint32_t    interval = 0;

    params.sock = &sock, params.topic = topic;
    params.data     = (uint8_t *) data;
    params.data_len = strlen(data);
    params.qos      = qos;
    params.interval = interval;
    publish_cb(&params);
    for(int i=0;i<5;i++){

        sprintf(qwes,"{\"id\":%d}",i);
        const char *datas=qwes;
        params.data = (uint8_t *) datas;
        publish_cb(&params);
        nng_msleep(1000);
    }


    nng_mqtt_disconnect(&sock, 5, NULL);

    return 0;

}
